/**
 * 
 */
package com.aaron.client;

import com.aaron.client.exceptions.*;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;

import com.google.gwt.user.client.Timer;

import com.bouwkamp.gwt.user.client.ui.RoundedPanel;
import java.util.*;
import org.gwtwidgets.client.ui.LightBox;
import com.google.gwt.user.client.Window;

/**
 * @author aaron
 * 
 */
public class WorkspacePanel extends Composite {
	private String auth;
	private User user;
	
	private class AddProjectPopup extends PopupPanel {
		private TextBox name_box;
		private TextBox url_box;
		private TextBox username_box;
		private PasswordTextBox password_box;

		public AddProjectPopup() {
			super(true);
			FlexTable table = new FlexTable();
			table.setWidget(0, 0, new Label("Add Project"));
			// table.getFlexCellFormatter().setColSpan(0, 0, 2);
			//name
			table.setWidget(1, 0, new Label("Project Name"));
			name_box = new TextBox();
			table.setWidget(1, 1, name_box);
			// svn
			table.setWidget(2, 0, new Label("SVN url"));
			url_box = new TextBox();
			table.setWidget(2, 1, url_box);
			// username
			table.setWidget(3, 0, new Label("Username"));
			username_box = new TextBox();
			table.setWidget(3, 1, username_box);
			// password
			table.setWidget(4, 0, new Label("Password"));
			password_box = new PasswordTextBox();
			table.setWidget(4, 1, password_box);
			// add
			table.setWidget(5, 1, new Button("Add", new ClickListener() {
				public void onClick(Widget sender) {
					//add the pending project to the project list
					project_list.addPendingProject(name_box.getText(), url_box.getText());
					// check out the project and cache on server, update
					// database
					SubversionServiceAsync svn_service = SubversionService.Util
							.getInstance();
					//String name, String svn_url, String svn_username, String svn_password, String auth, AsyncCallback callback
					svn_service.checkout(name_box.getText(), url_box.getText(), username_box
							.getText(), password_box.getText(), auth, 
							new AsyncCallback() {
								public void onSuccess(Object result) {
									//remove the pending project
									project_list.removePendingProject(name_box.getText());
									
									//update the projectList
									update();
								}

								public void onFailure(Throwable caught) {
									//remove the pending project
									project_list.removePendingProject(name_box.getText());
									
									// show reason why the new SVN project could
									// not be added
									try{
										throw caught;
									}
									catch(SVNException e){
										Window.alert("SVN Project could not be added: "+e.getMessage());
									}
									catch (Throwable e) {
										// last resort -- a very unexpected exception
										Window.alert("SVN Project could not be added. Unknown error.");
								    }
									
								}
							});
					hide();
				}
			}));
			// cancel
			table.setWidget(5, 2, new Button("Cancel", new ClickListener() {
				public void onClick(Widget sender) {
					hide();
				}
			}));

			setWidget(table);
			setStyleName("vivcode-popup");
		}
	}

	private LightBox add_project_dialog;

	private class ProjectLinks extends Composite {

		private HorizontalPanel panel = new HorizontalPanel();

		public ProjectLinks() {
			add_project_dialog = new LightBox(new AddProjectPopup());
			Hyperlink add_project = new Hyperlink("Add Project", "new-project");
			add_project.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					// display add project dialog
					add_project_dialog.show();
				}
			});
			panel.add(add_project);
			Hyperlink remove_project = new Hyperlink("Remove Project","");
			remove_project.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					//if any projects are selected
					if(project_list.getSelectedProjectNames().size()>0){
						//display are you sure dialog
						if(Window.confirm("Are you sure you wish to remove these projects?")){
							//get project names
							ArrayList names=project_list.getSelectedProjectNames();
							//for each project, delete it via RPC
							ProjectServiceAsync projectService=ProjectService.Util.getInstance();
							for(int i=0; i<names.size(); i++){
								projectService.deleteProject((String)names.get(i), auth, new AsyncCallback() {
									public void onSuccess(Object result) {
										// update the projectList
										update();
									}

									public void onFailure(Throwable caught) {
										// show reason why the new SVN project could
										// not be deleted
										Exception e=(Exception)caught;
										Window.alert("SVN Project could not be deleted: "+e.getMessage());
									}
								});
							}
						}
					}
				}
			});
			panel.add(remove_project);
			panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
			panel.add(new Hyperlink("All Projects", "all-projects"));
			panel.addStyleName("vivcode-panel");
			panel.addStyleName("vivcode-dark-panel");

			// flow.setWidth("100%");
			initWidget(panel);
		}
	}

	private class ProjectList extends Composite {
		private class PendingProjectPanel extends Composite{
			private class SwapIcons extends Timer{
				public void run() {
					//remove current icon
			        items.remove((Widget)icons.toArray()[current_icon]);
			        current_icon++;
			        current_icon%=2;
			        //insert the new icon at the begining
			        items.insert((Widget)icons.toArray()[current_icon], 0);
			      }
			}
			private String project_name;
			private HorizontalPanel items=new HorizontalPanel();
			private Image icon1=new Image("icons/server.png");
			private Image icon2=new Image("icons/server_link.png");
			private ArrayList icons=new ArrayList();
			private int current_icon=0;
			private Label project_name_label;
			private Label svn_url_label;
			public PendingProjectPanel(String project_name, String svn_url){
				this.project_name=project_name;
				project_name_label=new Label(project_name);
				svn_url_label=new Label(svn_url);
				project_name_label.addStyleName("light-text");
				svn_url_label.addStyleName("light-text");
				items.add(icon1);
				items.add(project_name_label);
				items.add(svn_url_label);
				initWidget(items);
				
				icons.add(icon1);
				icons.add(icon2);
				//swap icons every x milliseconds
				Timer t = new SwapIcons();
				t.scheduleRepeating(1000);
			}
			public String getName(){
				return project_name;
			}
		}
		
		private static final int VISIBLE_PROJECT_COUNT = 10;

		private int startIndex = -1;

		private VerticalPanel panel=new VerticalPanel();
		private VerticalPanel pending_projects_panel=new VerticalPanel();
		private FlexTable table = new FlexTable();
		
		private ArrayList selected_projects=new ArrayList();

		public ProjectList() {
			panel.add(pending_projects_panel);
			panel.add(table);
			
			//create the project check boxes
			for(int i=0; i<VISIBLE_PROJECT_COUNT; i++){
				selected_projects.add(new CheckBox());
			}
			// Create the header row.
			CheckBox select_all=new CheckBox();
			select_all.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					CheckBox select_all=(CheckBox)sender;
					if(select_all.isChecked()){
						for(int i=0; i<VISIBLE_PROJECT_COUNT; i++){
							CheckBox check_box=(CheckBox)selected_projects.get(i);
							check_box.setChecked(true);
						}
					}
					else{
						for(int i=0; i<VISIBLE_PROJECT_COUNT; i++){
							CheckBox check_box=(CheckBox)selected_projects.get(i);
							check_box.setChecked(false);
						}
					}
				}});
			table.setWidget(0, 0, select_all);
			table.setText(0, 1, "Active Projects");
			table.setText(0, 2, "Owner / Collaborators / Viewers");
			table.setText(0, 3, "Last Edited");
			table.getRowFormatter().addStyleName(0, "vivcode-panel");
			table.getRowFormatter().addStyleName(0, "vivcode-light-panel");
			// Initialize the rest of the rows.
			for (int i = 0; i < VISIBLE_PROJECT_COUNT; ++i) {
				table.setText(i + 1, 0, "");
				table.setText(i + 1, 1, "");
				table.setText(i + 1, 2, "");
				table.setText(i + 1, 3, "");
				table.getCellFormatter().setWordWrap(i + 1, 0, false);
				table.getCellFormatter().setWordWrap(i + 1, 1, false);
				table.getCellFormatter().setWordWrap(i + 1, 2, false);
				table.getCellFormatter().setWordWrap(i + 1, 3, false);
				//table.getFlexCellFormatter().setColSpan(i + 1, 2, 2);
			}
			initWidget(panel);
			update(auth);
		}
		public ArrayList getSelectedProjectNames(){
			ArrayList names=new ArrayList();
			for(int i=0; i<VISIBLE_PROJECT_COUNT; ++i) {
				CheckBox check_box=(CheckBox)selected_projects.get(i);
				if(check_box.isChecked()){
					names.add(table.getText(i+1,1));
				}
			}
			return names;
		}
		public void addPendingProject(String project_name, String svn_url){
			pending_projects_panel.add(new PendingProjectPanel(project_name, svn_url));
		}
		public void removePendingProject(String project_name){
			Iterator itr=pending_projects_panel.iterator();
			while(itr.hasNext()){
				PendingProjectPanel pending_project_panel=(PendingProjectPanel)itr.next();
				if(pending_project_panel.getName()==project_name){
					pending_projects_panel.remove(pending_project_panel);
				}
			}
		}

		/**
		 * Performs an RPC call to the workspace service to update the user's
		 * workspace
		 * 
		 */
		public void update(String auth) {
			WorkspaceServiceAsync workspaceService = WorkspaceService.Util
					.getInstance();
			workspaceService.getWorkspace(auth, new AsyncCallback() {
				public void onSuccess(Object result) {
					// fetch the workspace
					Workspace workspace = (Workspace) result;
					ArrayList project_proxies = workspace.getProjectProxies();
					// Show the visibleprojects.
					int i = 0;
					for (; i < VISIBLE_PROJECT_COUNT; ++i) {
						// Don't read past the end.
						if (startIndex + i +1 >= project_proxies.size()) {
							break;
						}
						ProjectProxy item = (ProjectProxy) project_proxies.get(i);

						// Add a new row to the table, then set each of its
						// columns to the
						// email's sender and subject values.
						Hyperlink open_project = new Hyperlink(item.getName(), "");
						open_project.addClickListener(new ClickListener() {
							public void onClick(Widget sender) {
								// display editor
								Hyperlink link=(Hyperlink)sender;
								Window.open(VivCode.getCurrentPath()+"?edit="+link.getText()+"&auth="+VivCode.getAuth(), link.getText(), "");
							}
						});
						
						table.setWidget(i + 1, 0, (Widget)selected_projects.get(i));
						table.setWidget(i + 1, 1, open_project);
						String owner=item.getOwner();
						String collaborators="";
						String viewers="";
						if(item.getCollaborators().isEmpty()){
							collaborators="none";
						}
						else{
							Iterator itr=item.getCollaborators().iterator();
							while(itr.hasNext()){
								Object obj=itr.next();
								if(obj instanceof String){
									String name=(String)obj;
									collaborators+=name+" ";
								}
							}
						}
						if(item.getViewers().isEmpty()){
							viewers="none";
						}
						else{
							Iterator itr=item.getViewers().iterator();
							while(itr.hasNext()){
								Object obj=itr.next();
								if(obj instanceof String){
									String name=(String)obj;
									viewers+=name+" ";
								}
							}
						}
						
						collaborators.trim();
						viewers.trim();
						String users=owner+" / "+collaborators+" / "+viewers;
						users.replaceAll(user.getName(), "me");
						table.setText(i + 1, 2, users);
						Date now=new Date();
						//2007-04-19 23:11:38
						String[] parts=item.getLastUpdate().split("[ :-]");
						Date last_update=new Date(Integer.parseInt(parts[0])-1900, Integer.parseInt(parts[1]), Integer.parseInt(parts[2]), Integer.parseInt(parts[3]), Integer.parseInt(parts[4]), Integer.parseInt(parts[5]));
						long interval=last_update.getTime()-now.getTime();
						table.setText(i + 1, 3, prettyInterval(interval)+" by "+item.getLastEditor());
					}

					// Clear any remaining slots.
					for (; i < VISIBLE_PROJECT_COUNT; ++i) {
						table.setHTML(i + 1, 0, "&nbsp;");
						table.setHTML(i + 1, 1, "&nbsp;");
						table.setHTML(i + 1, 2, "&nbsp;");
						table.setHTML(i + 1, 3, "&nbsp;");
					}
					//TODO check if there are any contingencies for this action
					//reset the check boxes
					for(i=0; i<VISIBLE_PROJECT_COUNT; i++){
						CheckBox check_box=(CheckBox)selected_projects.get(i);
						check_box.setChecked(false);
					}
				}

				public void onFailure(Throwable caught) {
					Exception e=(Exception)caught;
					Window.alert("Workspace.update(): failure: "+e.getMessage());
				}
			});
		}
		
	}

	private RoundedPanel rounded_panel;
	private ProjectList project_list;

	public WorkspacePanel(String auth) {
		this.auth=auth;
		this.user=new User();
		UserServiceAsync sessionService =UserService.Util.getInstance();
		sessionService.getUser(auth, new AsyncCallback(){
			public void onSuccess(Object result){
				user=(User)result;
			}
			public void onFailure(Throwable caught) {
				//TODO do something here?
			}
		});
		VerticalPanel root = new VerticalPanel();
		root.addStyleName("vivcode-panel");
		root.add((new Label("Projects")));
		VerticalPanel vertical_panel = new VerticalPanel();
		ProjectLinks project_links_top = new ProjectLinks();
		project_links_top.addStyleName("align-top");
		vertical_panel.add(project_links_top);
		project_list = new ProjectList();
		project_list.addStyleName("vivcode-variable-height-panel");
		project_list.addStyleName("vivcode-maxwidth");
		vertical_panel.add(project_list);

		ProjectLinks project_links_bottom = new ProjectLinks();
		project_links_top.addStyleName("align-bottom");
		vertical_panel.add(project_links_bottom);
		vertical_panel.setHeight("50%");
		rounded_panel = new RoundedPanel(vertical_panel);
		rounded_panel.addStyleName("vivcode-workspace-panel");
		root.add(rounded_panel);
		initWidget(root);

	}
	public void update(){
		project_list.update(auth);
	}
	private static String prettyInterval(long interval){
		//convert from milliseconds to seconds
		long seconds=interval/1000;
		if(seconds<60){
			return "<1 minute ago";
		}
		//convert to minutes
		long minutes=seconds/60;
		if(minutes<60){
			return minutes+" minutes ago";
		}
		//convert to hours
		long hours=minutes/60;
		if(hours<24){
			return hours+" hours ago";
		}
		//convert to days
		long days=hours/24;
		if(days<14){
			return days+" days ago";
		}
		//convert to weeks
		long weeks=days/7;
		if(days<30){
			return weeks+" weeks ago";
		}
		//convert to months
		long months=days/30;
		if(months<12){
			return months+" months ago";
		}
		//convert to years
		long years=days/365;
		return years+" years ago";
	}
}
